﻿using System.Collections.Generic;
using System;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Xml;

namespace Strom.Core.Config
{
    public static class AutoConfig
    {
        private static readonly IEnumerable<FieldInfo> ConfigFields;

        static AutoConfig()
        {
            ConfigFields = GetConfigFields();
        }

        public static void ReadConfig(string fileName)
        {
            if (!File.Exists(fileName))
                SaveConfig(fileName);

            using(var reader = new XmlTextReader(File.OpenRead(fileName)))
            {
                reader.ReadStartElement();
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.EndElement)
                    {
                        reader.ReadEndElement();
                        continue;
                    }

                    string name = reader.Name;
                    string type = reader.GetAttribute("type");
                    string value = reader.ReadString();

                    FieldInfo currentField =
                        ConfigFields.DefaultIfEmpty(null).FirstOrDefault(
                            current => current.Name == name && current.FieldType.ToString() == type);

                    if (currentField != null && value != "INVALID_TYPE")
                    {
                        if (type == typeof (string).ToString())
                            currentField.SetValue(null, value);
                        else if (type == typeof (int).ToString())
                            currentField.SetValue(null, int.Parse(value));
                        else if (type == typeof (long).ToString())
                            currentField.SetValue(null, long.Parse(value));
                        else if (type == typeof (short).ToString())
                            currentField.SetValue(null, short.Parse(value));
                        else if (type == typeof (byte).ToString())
                            currentField.SetValue(null, byte.Parse(value));
                    }

                    reader.ReadEndElement();
                }
            }
        }

        public static void SaveConfig(string fileName)
        {
            var writer = new XmlTextWriter(File.Create(fileName), Encoding.UTF8) { Formatting = Formatting.Indented };
            writer.WriteStartElement("Config");

            foreach (var var in GetConfigVariables())
            {
                writer.WriteStartElement(var.Name);
                writer.WriteAttributeString("type", var.Type);
                writer.WriteString(var.Value);
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
            writer.Close();
        }

        static IEnumerable<ConfigVariable> GetConfigVariables()
        {
            return ConfigFields.Select(field => new ConfigVariable(field.Name, field.FieldType.ToString(), field.GetValue(null))).ToList();
        }

        static IEnumerable<FieldInfo> GetConfigFields()
        {
            var fields = new List<FieldInfo>();

            foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.GetTypes().Where(current => current.IsAbstract && current.IsSealed)))
                fields.AddRange(type.GetFields().Where(current => current.IsStatic && current.GetCustomAttributes(typeof (XmlConfigVariable), false).Length > 0));
            
            return fields;
        }
    }
}
